package cn.mesmile.lock.model.packet.config;

import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer;
import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.handler.TableNameHandler;
import com.baomidou.mybatisplus.extension.plugins.handler.TenantLineHandler;
import com.baomidou.mybatisplus.extension.plugins.inner.*;
import com.fasterxml.jackson.databind.SerializationFeature;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.LongValue;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;
import java.util.Map;

/**
 * @author zb
 * @date 2020/12/22 18:31
 * @Description
 */
@Slf4j
@Configuration
public class NewMybatisPlusConfig {

    public static ThreadLocal<String> myTableName = new ThreadLocal<>();

    /**
     *  序列化枚举保存到数据库
     * @return
     */
    @Bean
    public Jackson2ObjectMapperBuilderCustomizer customizer(){
        return builder -> builder.featuresToEnable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);
    }

    /**
     * 自定义ID 生成器
     * @return
     */
//    @Bean
//    public IdentifierGenerator identifierGenerator() {
//        return new CustomIdGenerator();
//    }

    /**
     * 自动分页: PaginationInnerInterceptor
     * 多租户: TenantLineInnerInterceptor
     * 动态表名: DynamicTableNameInnerInterceptor
     * 乐观锁: OptimisticLockerInnerInterceptor
     * sql性能规范: IllegalSQLInnerInterceptor
     * 防止全表更新与删除: BlockAttackInnerInterceptor
     *
     * 使用多个功能需要注意顺序关系,建议使用如下顺序
     *
     *  1.多租户,动态表名
     *  2.分页,乐观锁
     *  3.sql性能规范,防止全表更新与删除
     */

    /**
     * 新的分页插件,一缓和二缓遵循mybatis的规则,
     * 需要设置 MybatisConfiguration#useDeprecatedExecutor = false 避免缓存出现问题(该属性会在旧插件移除后一同移除)
     */
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();

        // 获取租户拦截器
        TenantLineInnerInterceptor tenantLineInnerInterceptor = getTenantLineInnerInterceptor();
        // 1.先添加租户拦截器
        interceptor.addInnerInterceptor(tenantLineInnerInterceptor);

        // 获取动态表名
        DynamicTableNameInnerInterceptor dynamicTableNameInnerInterceptor = getDynamicTableNameInnerInterceptor();
        // 2.添加动态表名拦截器
        interceptor.addInnerInterceptor(dynamicTableNameInnerInterceptor);

        // 获取分页拦截器
        PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
        // 3.添加分页拦截器
        interceptor.addInnerInterceptor(paginationInnerInterceptor);

        // 4.添加乐观锁插件
        OptimisticLockerInnerInterceptor optimisticLockerInnerInterceptor = new OptimisticLockerInnerInterceptor();
        interceptor.addInnerInterceptor(optimisticLockerInnerInterceptor);

        // 5.防止全表更新与删除
        BlockAttackInnerInterceptor blockAttackInnerInterceptor = new BlockAttackInnerInterceptor();
        interceptor.addInnerInterceptor(blockAttackInnerInterceptor);

        return interceptor;
    }


    @Bean
    public ConfigurationCustomizer configurationCustomizer() {
        return configuration -> configuration.setUseDeprecatedExecutor(false);
    }

    /**
     * 性能分析插件,SQL 执行性能分析，开发环境使用，线上不推荐
     * @return
     */
//    @Bean
//    @Profile({"dev","test"})// 设置 dev test 环境开启
//    public PerformanceInterceptor performanceInterceptor() {
//        return new PerformanceInterceptor();
//    }

    /**
     * 动态表名相关设置
     * @return
     */
    private DynamicTableNameInnerInterceptor getDynamicTableNameInnerInterceptor() {
        Map<String, TableNameHandler> tableNameHandlerMap = new HashMap<>();

        DynamicTableNameInnerInterceptor dynamicTableNameInnerInterceptor = new DynamicTableNameInnerInterceptor();
        TableNameHandler tableNameHandler = new TableNameHandler() {
            @Override
            public String dynamicTableName(String sql, String tableName) {
                log.info("原表执行的 sql:  {}", sql);
                log.info("原表的名称 tableName:  {}", tableName);
                // 如果返回的值为空，则不进行替换  这里返回的事 动态表名
                return myTableName.get();
            }
        };
        tableNameHandlerMap.put("employee",tableNameHandler);
        dynamicTableNameInnerInterceptor.setTableNameHandlerMap(tableNameHandlerMap);

        return dynamicTableNameInnerInterceptor;

    }

    /**
     *  租户拦截器相关
     * @return
     */
    private TenantLineInnerInterceptor getTenantLineInnerInterceptor() {
        TenantLineHandler tenantLineHandler = new TenantLineHandler() {
            @Override
            public Expression getTenantId() {
                return new LongValue(1);
            }

            @Override
            public String getTenantIdColumn() {
                return "tenant_id";
            }

            @Override
            public boolean ignoreTable(String tableName) {
                if ("user".equals(tableName)){
                    return false;
                }
                // 返回true代表忽略所有表，false表示所有表都要加上租户id
                return true;
            }
        };
        return new TenantLineInnerInterceptor(tenantLineHandler);
    }


}
